package com.skytech.tax.customsdatawarehouse.singlewindow.customsdeclarations.domain.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.skytech.tax.customsdatawarehouse.common.util.SecurityUtil;
import com.skytech.tax.customsdatawarehouse.singlewindow.customsdeclarations.domain.dao.*;
import com.skytech.tax.customsdatawarehouse.singlewindow.customsdeclarations.domain.entity.*;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author Lianhong
 * @since 2021/6/10
 */
@Service("singleWindow.ieCustomsDeclarationService")
public class IECustomsDeclarationService {

    private static final Logger LOGGER = LoggerFactory.getLogger(IECustomsDeclarationService.class);

    @Value("${customsdatawarehouse.token}")
    private String token;

    @Resource(name = "singleWindow.ieCustomsDeclarationDao")
    private IECustomsDeclarationDao ieCustomsDeclarationDao;
    @Resource(name = "singleWindow.ieCustomsDeclarationSimpleDao")
    private IECustomsDeclarationSimpleDao ieCustomsDeclarationSimpleDao;
    @Resource(name = "singleWindow.ieCustomsDeclarationFileDao")
    private IECustomsDeclarationFileDao ieCustomsDeclarationFileDao;
    @Resource(name = "singleWindow.ieCustomsDeclarationAttDocFileDao")
    private IECustomsDeclarationAttDocFileDao ieCustomsDeclarationAttDocFileDao;
    @Resource(name = "singleWindow.ieCustomsDeclarationRetFileDao")
    private IECustomsDeclarationRetFileDao ieCustomsDeclarationRetFileDao;
    @Resource(name = "singleWindow.ieCustomsDeclarationRetDao")
    private IECustomsDeclarationRetDao ieCustomsDeclarationRetDao;

    public String getCustomsDeclarations() {
        List<IECustomsDeclaration> list = ieCustomsDeclarationDao.findAll();
        if (CollectionUtils.isEmpty(list)) return StringUtils.EMPTY;
        JSONArray customsDeclarations = new JSONArray();
        list.forEach(item -> customsDeclarations.add(JSON.parseObject(item.getCustomsDeclaration())));
        return SecurityUtil.encrypt3DES(token, JSON.toJSONString(customsDeclarations));
    }

    public String getCustomsDeclarations(List<String> cusCiqNos) {
        JSONArray customsDeclarations = this.customsDeclarations(cusCiqNos);
        if (CollectionUtils.isEmpty(customsDeclarations)) return StringUtils.EMPTY;
        return SecurityUtil.encrypt3DES(token, JSON.toJSONString(customsDeclarations));
    }

    @Transactional
    public String saveCustomsDeclaration(String declaration) {
        if (StringUtils.isEmpty(declaration)) return StringUtils.EMPTY;
        String customsDeclarationText = SecurityUtil.decrypt3DES(token, declaration);
        try {
            SingleWindowCustomsDeclaration singleWindowCustomsDeclaration = JSON.parseObject(customsDeclarationText, SingleWindowCustomsDeclaration.class);
            if (singleWindowCustomsDeclaration == null) return StringUtils.EMPTY;

            IECustomsDeclaration customsDeclaration = singleWindowCustomsDeclaration.buildCustomsDeclaration();
            if (customsDeclaration == null) return StringUtils.EMPTY;

            IECustomsDeclarationSimple customsDeclarationSimple = singleWindowCustomsDeclaration.buildCustomsDeclarationSimple();
            if (customsDeclarationSimple == null) return StringUtils.EMPTY;

            this.deleteByCusCiqNo(customsDeclaration.getCusCiqNo());

            ieCustomsDeclarationDao.save(customsDeclaration);
            ieCustomsDeclarationSimpleDao.save(customsDeclarationSimple);
            return SecurityUtil.encrypt3DES(token, customsDeclaration.getCustomsDeclaration());
        } catch (Exception e) {
            LOGGER.error("保存进出口报关单错误", e);
            return StringUtils.EMPTY;
        }
    }

    public String getCustomsDeclaration(String cusCiqNo) {
        IECustomsDeclaration customsDeclaration = ieCustomsDeclarationDao.findByCusCiqNo(cusCiqNo);
        if (customsDeclaration == null) return StringUtils.EMPTY;
        return SecurityUtil.encrypt3DES(token, customsDeclaration.getCustomsDeclaration());
    }

    public void deleteByCusCiqNo(String cusCiqNo) {
        ieCustomsDeclarationDao.delete(cusCiqNo);
        ieCustomsDeclarationSimpleDao.delete(cusCiqNo);
    }

    public boolean existsCustomsDeclaration(String cusCiqNo, String updateTime, String cusDecStatus) {
        return ieCustomsDeclarationSimpleDao.exists(cusCiqNo, updateTime, cusDecStatus);
    }

    public String existsCustomsDeclarations(List<IECustomsDeclarationSimple> simpleList) {
        if (CollectionUtils.isEmpty(simpleList)) return StringUtils.EMPTY;
        List<List<IECustomsDeclarationSimple>> parts = Lists.partition(simpleList, 500);
        List<String> result = new ArrayList<>();
        parts.forEach(item -> result.addAll(ieCustomsDeclarationSimpleDao.exists(item)));
        return StringUtils.join(result, ",");
    }

    public void saveCustomsDeclarationFile(String cusCiqNo, String storedFile) {
        IECustomsDeclarationFile customsDeclarationFile = new IECustomsDeclarationFile(cusCiqNo, storedFile);
        ieCustomsDeclarationFileDao.save(customsDeclarationFile);
    }

    public String customsDeclarationFile(String cusCiqNo) {
        IECustomsDeclarationFile customsDeclarationFile = ieCustomsDeclarationFileDao.findByCusCiqNo(cusCiqNo);
        return SecurityUtil.encrypt3DES(token, JSON.toJSONString(customsDeclarationFile));
    }

    public boolean customsDeclarationFileStored(String cusCiqNo) {
        return ieCustomsDeclarationFileDao.exists(cusCiqNo);
    }

    public void deleteCustomsDeclarationFile(String cusCiqNo) {
        ieCustomsDeclarationFileDao.delete(cusCiqNo);
    }

    public String receiptNoticeFile(String cusRetSeqNo) {
        return ieCustomsDeclarationRetFileDao.findByCusRetSeqNo(cusRetSeqNo);
    }

    public void saveReceiptNoticeFile(String cusRetSeqNo, String storedFile) {
        IECustomsDeclarationRetFile customsDeclarationRetFile = new IECustomsDeclarationRetFile(cusRetSeqNo, storedFile);
        ieCustomsDeclarationRetFileDao.save(customsDeclarationRetFile);
    }

    public boolean receiptNoticeFileStored(String cusRetSeqNo) {
        return ieCustomsDeclarationRetFileDao.exists(cusRetSeqNo);
    }

    public String attachedDocFile(String attEdocId) {
        return ieCustomsDeclarationAttDocFileDao.findByAttEdocId(attEdocId);
    }

    public void deleteAttachedDocFile(String attEdocId) {
        ieCustomsDeclarationAttDocFileDao.delete(attEdocId);
    }

    public void saveAttachedDocFile(String attEdocId, String storedFile) {
        IECustomsDeclarationAttDocFile customsDeclarationAttDocFile = new IECustomsDeclarationAttDocFile(attEdocId, storedFile);
        ieCustomsDeclarationAttDocFileDao.save(customsDeclarationAttDocFile);
    }

    public boolean attachedDocFileStored(String attEdocId) {
        return ieCustomsDeclarationAttDocFileDao.exists(attEdocId);
    }

    public String saveReceiptNotice(String ret) {
        if (StringUtils.isEmpty(ret)) return StringUtils.EMPTY;
        String receipt = SecurityUtil.decrypt3DES(token, ret);
        try {
            IECustomsDeclarationRet customsDeclarationRet = JSON.parseObject(receipt, IECustomsDeclarationRet.class);
            if (customsDeclarationRet == null) return StringUtils.EMPTY;

            this.ieCustomsDeclarationRetDao.delete(customsDeclarationRet.getCusCiqNo());

            ieCustomsDeclarationRetDao.save(customsDeclarationRet);
            return SecurityUtil.encrypt3DES(token, customsDeclarationRet.getRet());
        } catch (Exception e) {
            LOGGER.error("保存进出口报关单回执通知书错误", e);
            return StringUtils.EMPTY;
        }
    }

    private JSONArray customsDeclarations(List<String> cusCiqNos) {
        if (CollectionUtils.isEmpty(cusCiqNos)) return null;
        List<List<String>> parts = Lists.partition(cusCiqNos, 500);
        JSONArray customsDeclarations = new JSONArray();
        parts.forEach(cusCiqNoList -> {
            List<IECustomsDeclaration> list = ieCustomsDeclarationDao.findByCusCiqNos(cusCiqNoList);
            list.forEach(item -> customsDeclarations.add(JSON.parseObject(item.getCustomsDeclaration())));
        });
        return customsDeclarations;
    }

    public String attachedDocExists(List<String> cusCiqNos) {
        StopWatch stopWatch = new StopWatch(String.format("随附单据查询，共%d条数据", cusCiqNos.size()));
        stopWatch.start();

        JSONArray customsDeclarations = this.customsDeclarations(cusCiqNos);
        if (CollectionUtils.isEmpty(customsDeclarations)) return StringUtils.EMPTY;

        JSONArray result = new JSONArray();
        List<String> attEdocIds = new ArrayList<>();

        // 合并遍历逻辑，同时提取 attEdocId 并构造结果结构
        for (Object obj : customsDeclarations) {
            JSONObject item = (JSONObject) obj;
            String cusCiqNo = item.getString("cusCiqNo");

            JSONObject resultItem = new JSONObject();
            resultItem.put("cusCiqNo", cusCiqNo);
            result.add(resultItem);

            if (!item.containsKey("preDecDocVo")) {
                continue;
            }

            JSONArray preDecDocVo = item.getJSONArray("preDecDocVo");

            JSONArray updatedPreDecDocVo = new JSONArray();

            for (Object docObj : preDecDocVo) {
                JSONObject preDecDocVoItem = (JSONObject) docObj;

                if (!preDecDocVoItem.containsKey("attEdocId")) {
                    updatedPreDecDocVo.add(preDecDocVoItem);
                    continue;
                }

                String attEdocId = preDecDocVoItem.getString("attEdocId");
                if (StringUtils.isBlank(attEdocId)) {
                    updatedPreDecDocVo.add(preDecDocVoItem);
                    continue;
                }

                attEdocIds.add(attEdocId);
                // 暂时不设置 attDocExists，等批量查询后再填充
                updatedPreDecDocVo.add(preDecDocVoItem);
            }

            resultItem.put("preDecDocVo", updatedPreDecDocVo);
        }

        if (CollectionUtils.isEmpty(attEdocIds)) {
            stopWatch.stop();
            LOGGER.info("共 {} 条预录单数据，无随附单据，耗时：{} ms", cusCiqNos.size(), stopWatch.getLastTaskTimeMillis());
            return SecurityUtil.encrypt3DES(token, JSON.toJSONString(result));
        }

        Map<String, Boolean> attEdocIdExistsMap;
        try {
            attEdocIdExistsMap = ieCustomsDeclarationAttDocFileDao.batchCheckExists(attEdocIds);
        } catch (Exception e) {
            LOGGER.error("批量检查随附单据是否存在时发生异常", e);
            throw e;
        }

        // 填充 attDocExists 字段
        for (Object obj : result) {
            JSONObject resultItem = (JSONObject) obj;

            if (!resultItem.containsKey("preDecDocVo")) continue;
            JSONArray preDecDocVo = resultItem.getJSONArray("preDecDocVo");
            for (Object docObj : preDecDocVo) {
                if (!(docObj instanceof JSONObject)) continue;
                JSONObject preDecDocVoItem = (JSONObject) docObj;

                if (!preDecDocVoItem.containsKey("attEdocId")) continue;
                String attEdocId = preDecDocVoItem.getString("attEdocId");
                if (StringUtils.isBlank(attEdocId)) continue;

                preDecDocVoItem.put("attDocExists", attEdocIdExistsMap.getOrDefault(attEdocId, false));
            }
        }

        stopWatch.stop();
        LOGGER.info("共 {} 条预录单数据，判断随附单据({}条)是否存储，耗时：{} ms", cusCiqNos.size(), attEdocIds.size(), stopWatch.getLastTaskTimeMillis());
        return SecurityUtil.encrypt3DES(token, JSON.toJSONString(result));
    }


}
